home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Languguage OS 2
/
Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO
/
gnu
/
ae.lha
/
ae
/
AE
/
ae-mips.h
< prev
next >
Wrap
C/C++ Source or Header
|
1990-02-28
|
16KB
|
588 lines
/* AE program profiling system.
Machine-specific definitions for MIPS R2000/R3000 processors.
Copyright (C) 1990 by James R. Larus (larus@cs.wisc.edu)
AE and AEC are free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 1, or (at your option) any
later version.
AE and AEC are distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to James R.
Larus, Computer Sciences Department, University of Wisconsin--Madison,
1210 West Dayton Street, Madison, WI 53706, USA or to the Free
Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* $Header: /var/home/larus/AE/AE/RCS/ae-mips.h,v 2.0 90/02/09 17:21:37 larus Exp Locker: larus $ */
/* Define the base and bounds of the AE buffer that accumulates events in
the executing program. */
/* The pointer to the AE Buffer can either be in a register or in a
variable stored in memory. If it is in a register, AE_BUFFER_REG
contains the register's name, as a string. If it is in memory,
AE_BUFFER_VAR contains the variable's name as a string.
MAKE_AE_BUFFER_POINTER returns an rtx expression for this pointer. */
/* On MIPS, we use R23 (aka) as the pointer to AE buffer. The limit
is a fixed distance from the top of user memory, which is a negative
number. */
#define AE_BUFFER_REG "s7"
#undef AE_BUFFER_VAR
#define MAKE_AE_BUFFER_POINTER() gen_rtx (REG, Pmode, 23) /* 23 = s7 */
/* The end of the AE Buffer can either be pointed to by a register or
by a variable stored in memory. If it is in a register,
AE_BUFFER_BOUND_REG contains the register's name, as a string. If it
is in memory, AE_BUFFER_BOUND_VAR contains the variable's name as a
string. MAKE_AE_BOUND_POINTER returns an rtx expression for this
pointer. */
#undef AE_BUFFER_BOUND_REG
#undef AE_BUFFER_BOUND_VAR
#define MAKE_AE_BOUND_POINTER()
/* Alternatively, the end of the AE buffer can be a fixed distance
from the top of the stack. */
/* Here's the picture for MIPS:
Top of memory --> @0x80000000
(Reserved on MIPS) --> 4K
Environemnt --> 10K max ??
argv --> ?K max
ae_start frame --> 16 bytes
... padding ...
top of buffer --> @0x80000000-(32K-4K)
*/
#define STACK_TOP 0x80000000
/* Less than 32K to fit insn's 15-bit field */
#define AE_BUFFER_STACK_OFFSET 32768-4096
/* Size of AE buffer (bytes). */
#define AE_BUFFER_SIZE 0x100000 /* 1MB */
/* Size of a stack frame for the routine AE_START. */
#define AE_START_FRAME_SIZE (16 * sizeof (int))
/* Name of stack pointer register. */
#define SP_REG "sp"
/* One plus maximum number of instructions combine by peephole optimizer. */
#define MAX_PEEP 3
/* Return non-zero if register number REGNO can be defined upon
function entry. */
#define REGISTER_DEFINED_IN_CALL(REGNO) ((REGNO) == STACK_POINTER_REGNUM \
|| (REGNO) == FRAME_POINTER_REGNUM \
|| FUNCTION_ARG_REGNO_P ((REGNO)))
/* Define the characters that proceed comments and assembler directives. */
#define ASM_COMMENT_CHAR '#'
#define ASM_DIRECTIVE_CHAR '.'
/* Define the number of delayed instructions after a jump, conditional jump,
or call instruction. Do not define these values if the instructions have
no delays or the assembler hides them by doing code reorganization. */
#undef JUMP_DELAY_SLOTS
#undef CJUMP_DELAY_SLOTS
#undef CALL_DELAY_SLOTS
/* The size of most assembly instructions (in bytes). */
#define STD_ASM_INSN_LENGTH 4
/* Set of instruction-size pairs for instructions whose size is not
standard. The table must be sorted by instruction name. */
#define ASM_INSN_SIZE_EXCEPTIONS \
"abs", (char *) 3, \
"bge", (char *) 2, \
"bgeu", (char *) 2, \
"bgt", (char *) 2, \
"bgtu", (char *) 2, \
"ble", (char *) 2, \
"bleu", (char *) 2, \
"blt", (char *) 2, \
"bltu", (char *) 2, \
"div", (char *) 10, /* Guess */ \
"divu", (char *) 10, /* Guess */ \
"la", (char *) 2, \
"li", (char *) 2, \
"mul", (char *) 2, \
"mulo", (char *) 5, \
"mulou", (char *) 4, \
"neg", (char *) 2, \
"negu", (char *) 3, \
"rem", (char *) 10, /* Guess */ \
"remu", (char *) 10, /* Guess */ \
"rol", (char *) 3, \
"ror", (char *) 3, \
"seq", (char *) 2, \
"sge", (char *) 2, \
"sgeu", (char *) 2, \
"sgt", (char *) 2, \
"sgtu", (char *) 2, \
"sle", (char *) 2, \
"sleu", (char *) 2, \
"sne", (char *) 2, \
"ulh", (char *) 2, \
"ulhu", (char *) 2, \
"ulw", (char *) 2, \
"ush", (char *) 2, \
"usw", (char *) 2
/* Return non-zero if the assembly instruction is a branch that does
not execute its (normally) delayed slot instruction. */
#define BRANCH_IS_ANNULED(ASM_INSN) 0
/* Return a pointer to the function name if an assembly instruction is
a subroutine invocation. If it is not, return 0. */
#define ASM_INSN_IS_CALL(ASM_INSN) (strncmp ((ASM_INSN), "jal", 3) \
? 0 : (ASM_INSN) + 3)
/* Produce the schema corresponding the the standard function prologue
and epilogue. Record values that are need upon function entry. */
#define SCHEMA_PROLOGUE(RECORD_REG_ON_ENTRY) \
{ \
/* Code from FUNCTION_PROLOGUE: */ \
int frame_size = get_frame_size (); \
register int regno; \
register int mask = 0, fmask=0; \
extern char call_used_regs []; \
register int push_loc = 0, tsize = frame_size + 8; \
\
for (regno = 0; regno < 32; regno++) \
if (MUST_SAVE_REG_LOGUES \
|| (regs_ever_live [regno] && !call_used_regs [regno])) \
{tsize += 4; mask |= 1 << regno;} \
\
for (regno = 32; regno < FIRST_PSEUDO_REGISTER; regno += 2) \
if (regs_ever_live [regno] && !call_used_regs [regno]) \
{tsize += 8; fmask |= 1 << (regno-32);} \
\
if (THIS_VARARGS_SUSPECTED) tsize += 16; \
\
regno = STACK_POINTER_REGNUM; \
tsize = AL_ADJUST_ALIGN (tsize); \
\
push_loc = 0; \
\
if (frame_pointer_needed \
|| regs_ever_live [29] || regs_ever_live [30] \
|| fmask || mask \
|| (frame_size > 0)) \
record_sp (); \
\
for (regno = 31; regno >= 30; regno--) \
if (MUST_SAVE_REG_LOGUES \
|| (regs_ever_live [regno] && !call_used_regs [regno])) \
{ \
store_schema_int_offset (STACK_POINTER_REGNUM, push_loc, 0);\
push_loc += 4; \
} \
\
if (THIS_VARARGS_SUSPECTED) \
{ \
int fregno; \
simple_def_schema (9, 0, tsize); \
store_schema_int_offset (STACK_POINTER_REGNUM, tsize - 4, 0);\
for (fregno = 44; fregno< 48; fregno += 2) \
{ \
store_schema_int_offset (STACK_POINTER_REGNUM, push_loc, 1);\
push_loc += 8; \
} \
} \
\
for (regno = 29; regno >= 0; regno--) \
if (MUST_SAVE_REG_LOGUES \
|| (regs_ever_live [regno] && !call_used_regs [regno]))\
{ \
store_schema_int_offset (STACK_POINTER_REGNUM, push_loc, 0);\
push_loc += 4; \
} \
\
for (regno = 32; regno < FIRST_PSEUDO_REGISTER; regno += 2) \
if (regs_ever_live [regno] && !call_used_regs [regno]) \
{ \
store_schema_int_offset (STACK_POINTER_REGNUM, push_loc, 1);\
push_loc += 8; \
} \
\
if (frame_pointer_needed) \
simple_def_schema (FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM, tsize);\
\
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno ++) \
if (RECORD_REG_ON_ENTRY [regno] \
&& regno != STACK_POINTER_REGNUM \
&& regno != FRAME_POINTER_REGNUM) \
{ \
unknown_def_schema (regno); \
issue_event (gen_rtx (REG, Pmode, regno)); \
} \
}
#define SCHEMA_EPILOGUE() \
{ \
/* Code from FUNCTION_EPILOGUE: */ \
int frame_size = get_frame_size (); \
register int regno; \
register int mask = 0, fmask = 0; \
extern char call_used_regs []; \
register int push_loc ; \
\
extern int current_function_total_framesize; \
\
push_loc = 0; \
regno = STACK_POINTER_REGNUM; \
\
if (frame_pointer_needed) \
simple_def_schema (8, FRAME_POINTER_REGNUM, 0); \
\
for (regno = 0; regno < 32; regno++) \
if (MUST_SAVE_REG_LOGUES \
|| (regs_ever_live [regno] && !call_used_regs [regno])) \
mask |= 1 << regno; \
\
for (regno = 31; regno >= 0; regno--) \
{ \
if (MUST_SAVE_REG_LOGUES \
|| (regs_ever_live [regno] && !call_used_regs [regno]))\
{ \
load_schema_int_offset ((frame_pointer_needed ? 8 : STACK_POINTER_REGNUM),\
(frame_pointer_needed ? \
push_loc - current_function_total_framesize:\
push_loc), \
0); \
push_loc += 4; \
} \
if (THIS_VARARGS_SUSPECTED && (regno == 30)) \
push_loc += 16; \
} \
\
for (regno = 32; regno < FIRST_PSEUDO_REGISTER; regno += 2) \
if (regs_ever_live [regno] && !call_used_regs [regno]) \
fmask |= 1 << (regno-32); \
\
for (regno = 32; regno < FIRST_PSEUDO_REGISTER; regno += 2) \
if (regs_ever_live [regno] && !call_used_regs [regno]) \
{ \
load_schema_int_offset ((frame_pointer_needed ? 8 : STACK_POINTER_REGNUM),\
(frame_pointer_needed ? \
push_loc - current_function_total_framesize:\
push_loc), \
\
1); \
push_loc += 8; \
} \
\
if (frame_pointer_needed) \
simple_def_schema (STACK_POINTER_REGNUM, 8, 0); \
else \
if (regs_ever_live [29]|| regs_ever_live [30] \
|| fmask || mask \
|| (frame_size > 0)) \
simple_def_schema (STACK_POINTER_REGNUM, STACK_POINTER_REGNUM,\
current_function_total_framesize); \
}
/* Produce and write the the assembly output file code to record the
various types of events. */
/* Check that the AE buffer has SIZE bytes free. If not, empty the
buffer. */
#define GENERATE_SPACE_CHECK(COMMENT, SIZE) \
{ \
rtx xops [1]; \
rtx label = gen_label_rtx (); \
char buffer [256]; \
\
sprintf (buffer, ".set noat\t\t\t\t# %s Event w/ check", COMMENT);\
output_asm_insn (buffer, xops); \
\
xops [0] = ae_buffer_pointer; \
sprintf (buffer, "addu $1,%%0,%d", AE_BUFFER_STACK_OFFSET + CHUNK_SIZE);\
output_asm_insn (buffer, xops); \
\
xops [0] = label; \
output_asm_insn ("bgtz $1,%l0", xops); \
output_asm_insn (".set at", xops); \
\
output_asm_insn ("jal ae_flush_buffer", xops); \
\
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (label));\
}
/* Generate an event to record VALUE (an rtx register). */
#define GENERATE_EVENT(VALUE) \
{ \
rtx xops [2]; \
\
xops [0] = VALUE; \
xops [1] = ae_buffer_pointer; \
output_asm_insn ("usw\t%0,0(%1)", xops); \
\
xops [0] = ae_buffer_pointer; \
output_asm_insn ("addiu\t%0,%0,4\t\t# End Event", xops); \
}
/* Generate an event to record the integer VALUE, which should be
stored in BYTES bytes. */
#define GENERATE_SHORT_EVENT(VALUE, BYTES) \
{ \
rtx xops [2]; \
\
output_asm_insn (".set noat", xops); \
xops [0] = gen_rtx (CONST_INT, VOIDmode, VALUE); \
output_asm_insn ("addiu\t$1,$0,%0", xops); \
\
xops [0] = ae_buffer_pointer; \
if (BYTES == 1) \
output_asm_insn ("sb\t$1,0(%0)", xops); \
else \
output_asm_insn ("ush\t$1,0(%0)", xops); \
output_asm_insn (".set at", xops); \
\
xops [0] = ae_buffer_pointer; \
xops [1] = gen_rtx (CONST_INT, VOIDmode, BYTES); \
output_asm_insn ("addiu\t%0,%0,%1\t\t# End Short Event", xops);\
}
/* Generate an event to record ADDRESS, which is made computed from BASE and
OFFSET. */
#define GENERATE_ADDRESS_EVENT(ADDRESS, BASE, OFFSET) \
{ \
rtx xops [1]; \
\
output_asm_insn (".set noat", xops); \
xops [0] = ADDRESS; \
/* Causes assembler warning since LA is a macro, but produces \
correct code. */ \
output_asm_insn ("la\t$1,%0", xops); \
\
xops [0] = ae_buffer_pointer; \
output_asm_insn ("usw\t$1,0(%0)", xops); \
output_asm_insn (".set at", xops); \
\
xops [0] = ae_buffer_pointer; \
output_asm_insn ("addiu\t%0,%0,4\t\t# End Address Event", xops);\
}
/* Assembly code routines for aecrt0.o. */
#ifdef AE_START_ASM
.align 2
.globl ae_start
.ent ae_start
ae_start:
.set nomove /* Do not allow the assembler to move insns.*/
lw $4,0($sp)
la $gp,_gp
addiu $5,$sp,4
addiu $6,$5,4
sll $2,$4,2
addu $6,$6,$2
addiu $sp,$sp,-24
sw $0,20($sp)
sw $6,environ
sw $5,__Argv
sw $4,__Argc
sw $0,errno
jal ae_initialize /* Addition */
lw $5,__Argv /* ditto */
lw $4,__Argc /* ditto */
jal main
jal exit
move $4,$2
break 0
.set move
.end ae_start
#endif
#ifdef AE_FLUSH_BUFFER_ASM
.align 2
.globl ae_flush_buffer
.ent ae_flush_buffer
ae_flush_buffer:
/*PROLOGUE */
/* .mask 0xc0010000 */
subu $29,152 /*temp= 128,saveregs= 24, sfo= -8 */
sw $31,0($29)
sw $30,4($29)
sw $16,8($29)
/* .fmask 0x0 */
addiu $30,$29,152 /*Establish FramePTR */
/*END PROLOGUE */
.set noat
addiu $16,$30,0xff78 /*addsi3 $30,-136 -> $16 */
sw $1,4($16)
.set at
sw $2,8($16)
sw $3,12($16)
sw $4,16($16)
sw $5,20($16)
sw $6,24($16)
sw $7,28($16)
sw $8,32($16)
sw $9,36($16)
sw $10,40($16)
sw $11,44($16)
sw $12,48($16)
sw $13,52($16)
sw $14,56($16)
sw $15,60($16)
sw $17,68($16)
sw $18,72($16)
sw $19,76($16)
sw $20,80($16)
sw $21,84($16)
sw $22,88($16)
sw $24,96($16)
sw $25,100($16)
sw $26,104($16)
sw $27,108($16)
sw $28,112($16)
addiu $29,$29,0xfff0 /*subsi3 $29,16 -> $29 */
lw $4,ae_fd /*movsi ae_fd -> $4 */
lw $5,ae_buffer_base /*movsi ae_buffer_base -> $5 */
subu $6,$23,$5 /*subsi3 $23,$5 -> $6 */
jal write /* call write regle 2-call (VOIDmode) */
lw $23,ae_buffer_base /*movsi ae_buffer_base -> $23 */
.set noat
lw $1,4($16)
.set at
lw $2,8($16)
lw $3,12($16)
lw $4,16($16)
lw $5,20($16)
lw $6,24($16)
lw $7,28($16)
lw $8,32($16)
lw $9,36($16)
lw $10,40($16)
lw $11,44($16)
lw $12,48($16)
lw $13,52($16)
lw $14,56($16)
lw $15,60($16)
lw $17,68($16)
lw $18,72($16)
lw $19,76($16)
lw $20,80($16)
lw $21,84($16)
lw $22,88($16)
lw $24,96($16)
lw $25,100($16)
lw $26,104($16)
lw $27,108($16)
lw $28,112($16)
addiu $29,$29,0x10 /*addsi3 $29,16 -> $29 */
/*EPILOGUE */
addu $29,$0,$30 /* sp not trusted here */
/* .mask 0xc0010000 */
lw $31,-152($29)
lw $30,-148($29)
lw $16,-144($29)
/* .fmask 0x0 */
j $31
/*END EPILOGUE */
.end ae_flush_buffer
.comm ae_fd,8
.comm ae_buffer_base,8
#endif
/* Definitions for AEC. */
/* a.out file format is ECOFF, with the LDFCN library to find symbols. */
#define ECOFF_AOUT
#undef BSD_AOUT
/* Function call returns this many bytes after call instruction. */
/* We don't see delayed instructions on MIPS, so return to the next
instruction.*/
#define PC_OFFSET_AFTER_CALL 4
/* Return non-zero if register N is local to a function, e.g. can
have distinct values in different functions. */
#define REG_LOCAL_TO_FUNCTION(N) (!call_used_regs [(N)] \
|| (N) == STACK_POINTER_REGNUM)
/* Initialize registers before the generation program begins. */
#define INITIALIZE_REGISTERS() \
{ \
char buf [80]; \
output_set_value (0, "0"); \
sprintf (buf, "0x%x", symbol_address_or_die ("_gp")); \
output_set_value (28, buf); \
}